B       [0-1]
D       [0-9]
L       [a-zA-Z_$]
H       [a-fA-F0-9]
E       [Ee][+-]?{D}+
FS      (f|F|l|L)
IS      (u|U|l|L)*

%{
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "Support\dbuf_string.h"
#include "Parser.h"
#include "common.h"

#define TKEYWORD(token) return (isTargetKeyword(yytext) ? token : check_type())

extern char *fullSrcFileName;
extern char *filename;
extern int ignoreTypedefType;
extern int lineno;
extern int NestLevel;
int column = 0;         /* current column */
int fatalError = 0;		/* fatal Error number */
int fatalWarning = 0;	/* fatal Warning number */

/* global definitions */
char *lexFilename;
int lexLineno = 1;

/* local definitions */
static struct dbuf_s asmbuff; /* reusable _asm buffer */

/* forward declarations */
int yyerror(char *s);
static const char *stringLiteral(void);
static void count(void);
static void count_char(int);
static int process_pragma(const char *);
static int check_type(void);
static int isTargetKeyword(const char *s);
static int checkCurrFile(const char *s);
%}

%x asm
%%
_?"_asminline"         {
	count();
	
}
<asm>_?"_endasminline" {
	count();

}

"auto"         { count(); return(AUTO); }
"break"        { count(); return(BREAK); }
"case"         { count(); return(CASE); }
"char"         { count(); return(CHAR); }
"const"        { count(); return(CONST); }
"continue"     { count(); return(CONTINUE); }
"default"      { count(); return(DEFAULT); }
"do"           { count(); return(DO); }
"double"       { count(); /*werror(W_DOUBLE_UNSUPPORTED);*/return(LONG); }
"else"         { count(); return(ELSE); }
"enum"         { count(); return(ENUM); }
"extern"       { count(); return(EXTERN); }
"float"        { count(); /*werror(W_FLOAT_UNSUPPORTED);*/return(LONG); }
"for"          { count(); return(FOR); }
"goto"         { count(); return(GOTO); }
"if"           { count(); return(IF); }
"int"          { count(); return(INT); }
"long"         { count(); return(LONG); }
"register"     { count(); return(REGISTER); }
"return"       { count(); return(RETURN); }
"short"        { count(); return(SHORT); }
"signed"       { count(); return(SIGNED); }
"sizeof"       { count(); return(SIZEOF); }
"static"       { count(); return(STATIC); }
"struct"       { count(); return(STRUCT); }
"switch"       { count(); return(SWITCH); }
"typedef"      { count(); return(TYPEDEF); }
"union"        { count(); return(UNION); }
"unsigned"     { count(); return(UNSIGNED); }
"void"         { count(); return(VOID); }
"volatile"     { count(); return(VOLATILE); }
"while"        { count(); return(WHILE); }
"..."          { count(); return(VAR_ARGS); }
"__typeof"     { count(); return TYPEOF; }
{L}({L}|{D})*  {
	if (strchr(yytext, '$'))
    {
		yyerror("stray '$' in program");
    }
  count();
  return(check_type());
}
0[bB]{B}+{IS}? {
  count();
  yylval.val = constVal(yytext);
  return(CONSTANT);
}
0[xX]{H}+{IS}? 		{ count(); yylval.val = constVal(yytext); return(CONSTANT); }
0[0-7]*{IS}?     	{ count(); yylval.val = constVal(yytext); return(CONSTANT); }
[1-9]{D}*{IS}?      { count(); yylval.val = constVal(yytext); return(CONSTANT); }
'(\\.|[^\\'])+' 	{ count(); yylval.val = charVal (yytext); return(CONSTANT); /* ' make syntax highliter happy */ }
{D}+{E}{FS}?   		{ count(); /*yylval.val = constFloatVal(yytext)*/;return(CONSTANT); }
{D}*"."{D}+({E})?{FS}?  { count(); yylexerror("Floating point is not supported.");return(CONSTANT); }
{D}+"."{D}*({E})?{FS}?  { count(); yylexerror("Floating point is not supported.");return(CONSTANT); }
\"             			{ count();/* yylval.val=strVal(stringLiteral());*/ return(STRING_LITERAL); }
">>="          { count(); yylval.yyint = RIGHT_ASSIGN ; return(RIGHT_ASSIGN); }
"<<="          { count(); yylval.yyint = LEFT_ASSIGN  ; return(LEFT_ASSIGN); }
"+="           { count(); yylval.yyint = ADD_ASSIGN   ; return(ADD_ASSIGN); }
"-="           { count(); yylval.yyint = SUB_ASSIGN   ; return(SUB_ASSIGN); }
"*="           { count(); yylval.yyint = MUL_ASSIGN   ; return(MUL_ASSIGN); }
"/="           { count(); yylval.yyint = DIV_ASSIGN   ; return(DIV_ASSIGN); }
"%="           { count(); yylval.yyint = MOD_ASSIGN   ; return(MOD_ASSIGN); }
"&="           { count(); yylval.yyint = AND_ASSIGN   ; return(AND_ASSIGN); }
"^="           { count(); yylval.yyint = XOR_ASSIGN   ; return(XOR_ASSIGN); }
"|="           { count(); yylval.yyint = OR_ASSIGN    ; return(OR_ASSIGN); }
">>"           { count(); return(RIGHT_OP); }
"<<"           { count(); return(LEFT_OP); }
"++"           { count(); return(INC_OP); }
"--"           { count(); return(DEC_OP); }
"->"           { count(); return(PTR_OP); }
"&&"           { count(); return(AND_OP); }
"||"           { count(); return(OR_OP); }
"<="           { count(); return(LE_OP); }
">="           { count(); return(GE_OP); }
"=="           { count(); return(EQ_OP); }
"!="           { count(); return(NE_OP); }
";"            { count(); return(';'); }
"{"            { count(); NestLevel++ ; ignoreTypedefType = 0; return('{'); }
"}"            { count(); NestLevel--; return('}'); }
","            { count(); return(','); }
":"            { count(); return(':'); }
"="            { count(); return('='); }
"("            { count(); ignoreTypedefType = 0; return('('); }
")"            { count(); return(')'); }
"["            { count(); return('['); }
"]"            { count(); return(']'); }
"."            { count(); return('.'); }
"&"            { count(); return('&'); }
"!"            { count(); return('!'); }
"~"            { count(); return('~'); }
"-"            { count(); return('-'); }
"+"            { count(); return('+'); }
"*"            { count(); return('*'); }
"/"            { count(); return('/'); }
"%"            { count(); return('%'); }
"<"            { count(); return('<'); }
">"            { count(); return('>'); }
"^"            { count(); return('^'); }
"|"            { count(); return('|'); }
"?"            { count(); return('?'); }
^(#line.*"\n")|(#.*"\n") { count(); checkCurrFile(yytext); }

^[^(]+"("[0-9]+") : error"[^\n]+ 	{ count(); }
^[^(]+"("[0-9]+") : warning"[^\n]+ 	{ count(); }
"\r\n"         { count(); }
"\n"           { count(); }
[ \t\v\f]      { count(); }
\\ {
	int ch = input();
	if (ch == '\n')
		count_char(ch);
	else
	{
		yylexerror("stray '\\' in program");
		unput(ch);
	}
}
.              { count(); }
%%


#ifndef yytext_ptr
#define yytext_ptr yytext
#endif

static int checkCurrFile (const char *s)
{
	char temp[MAX_STRING_LEN];
//  int  lNum;
//  char *tptr;
//
//  /* skip '#' character */
//  if (*s++ != '#')
//    return 0;
//
//  /* check if this is a #line
//    this is not standard and can be removed in the future */
//#define LINE_STR  "line"
//#define LINE_LEN  ((sizeof LINE_STR) - 1)
//
//  if (strncmp(s, LINE_STR, LINE_LEN) == 0)
//    s += LINE_LEN;
//
//  /* get the line number */
//  lNum = strtol(s, &tptr, 10);
//  if (tptr == s || !isspace((unsigned char)*tptr))
//    return 0;
//  s = tptr;
//
//  /* adjust the line number */
//  lineno = lexLineno = lNum;
//
//  /* now see if we have a file name */
//  while (*s != '"' && *s)
//    ++s;
//
//  if (!*s)
//    {
//      /* no file name: return */
//      return 0;
//    }
//
//  /* skip the double quote */
//  ++s;
//
  /* get the file name and see if it is different from current one.
     in c1mode fullSrcFileName is NULL */

  memset(temp, 0, MAX_STRING_LEN);
  if (fullSrcFileName[0] == '"' && 
		fullSrcFileName[strlen(fullSrcFileName) - 1] == '"')
	{
		strncpy(temp, fullSrcFileName+1, strlen(fullSrcFileName) - 2);
		strncpy(fullSrcFileName, temp, MAX_STRING_LEN);
	}
	
  lexFilename = fullSrcFileName; 
  filename = lexFilename;
  
  return 0;
}

static void count_char(int ch)
{
  switch (ch)
    {
    case '\n':
      column = 0;
      lineno = ++lexLineno;
      break;

    case '\t':
      column += 8 - (column % 8);
      break;

    default:
      ++column;
      break;
    }
}

static void count(void)
{
  const char *p;

  for (p = yytext; *p; ++p)
    count_char(*p);
}

static int check_type(void)
{
  symbol *sym = findSym(SymbolTab, NULL, yytext);

  strncpyz(yylval.yychar, yytext, MAX_NAME);

  /* check if it is in the table as a typedef */
  if (!ignoreTypedefType && sym && IS_SPEC (sym->etype)
      && SPEC_TYPEDEF (sym->etype) && findSym(TypedefTab, NULL, yytext))
    return (TYPE_NAME);
  else
    return(IDENTIFIER);
}


static int isTargetKeyword(const char *s)
{
	return 0;
}

int yywrap(void)
{
	return 1;
}

int yyerror(char *s)
{
  fflush(stdout);

  if(YY_VC_ERROR_STYLE)
    fprintf(stderr, "\n%s(%d) : %s: token -> '%s' ; column %d\n",
      lexFilename, lexLineno, s, yytext, column);
  else
    fprintf(stderr, "\n%s:%d: %s: token -> '%s' ; column %d\n",
      lexFilename, lexLineno, s ,yytext, column);
  fatalError++;

  return 0;
}

/*-------------------------------------------------------------------------------
ccerror - Output a standard eror message with variable number of arguements.
           Use a specified filename and line number instead of the default.

-------------------------------------------------------------------------------
*/
void ccerror(char *newFilename, int newLineno, const char *format, ...)
{
    va_list marker;
    char buff[BUFSIZ];  
	
	/* print header */
	if(YY_VC_ERROR_STYLE)
		fprintf(DEFAULT_ERROR_OUT, "\n%s(%d) error %d: ",
		  newFilename, newLineno, fatalError);
	else
		fprintf(DEFAULT_ERROR_OUT, "\n%s:%d error %d: ",
		  newFilename, newLineno, fatalError);
		  
    va_start(marker, format);
    vsprintf(buff, format, marker);
    va_end(marker);
    
    fprintf(DEFAULT_ERROR_OUT, buff);
    //fprintf(DEFAULT_ERROR_OUT, "\n");
    
    fatalError++;
}

void yylexerror(const char *format, ...)
{    
    va_list marker;  
    char buff[BUFSIZ];      
	
	if(YY_VC_ERROR_STYLE)
		fprintf(DEFAULT_ERROR_OUT, "\n%s(%d) error %d: ",
		  lexFilename, lexLineno, fatalError);
	else
		fprintf(DEFAULT_ERROR_OUT, "\n%s:%d error %d: ",
		  lexFilename, lexLineno, fatalError);
		  
    va_start(marker, format);
    vsprintf(buff, format, marker);
    va_end(marker);

    fprintf(DEFAULT_ERROR_OUT, buff);
    fprintf(DEFAULT_ERROR_OUT, " ; column %d", column);
    //fprintf(DEFAULT_ERROR_OUT, "\n"); 
    
    fatalError++;
}

void yylexwarning(const char *format, ...)
{    
    va_list marker;  
    char buff[BUFSIZ];      
	
	if(YY_VC_ERROR_STYLE)
		fprintf(DEFAULT_ERROR_OUT, "\n%s(%d) warning: ",
		  lexFilename, lexLineno);
	else
		fprintf(DEFAULT_ERROR_OUT, "\n%s:%d warning: ",
		  lexFilename, lexLineno);
		  
    va_start(marker, format);
    vsprintf(buff, format, marker);
    va_end(marker);

    fprintf(DEFAULT_ERROR_OUT, buff);
    fprintf(DEFAULT_ERROR_OUT, " ; column %d", column);
    //fprintf(DEFAULT_ERROR_OUT, "\n"); 
    
    fatalWarning++;
}

void yylexsumary()
{
	printf("Compile complete! %i error(s), %i warning(s)", fatalError, fatalWarning);
}
